﻿Imports Microsoft.Win32
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Text
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Workflow.ComponentModel

Namespace System.Workflow.ComponentModel.Design
    <ToolboxItem(False)> _
    Friend NotInheritable Class TabStrip
        Inherits Control
        ' Events
        Public Custom Event TabChange As SelectionChangeEventHandler([Of] TabSelectionChangeEventArgs)

        ' Methods
        Public Sub New(ByVal orientation As Orientation, ByVal tabSize As Integer)
            MyBase.SuspendLayout
            Me.orientation = orientation
            Me.reqTabItemSize = Math.Max(tabSize, &H12)
            Me.Font = New Font(Me.Font.FontFamily, CSng(((Me.reqTabItemSize * 2) / 3)), GraphicsUnit.Pixel)
            Me.tabItemList = New ItemList([Of] ItemInfo)(Me)
            AddHandler Me.tabItemList.ListChanging, New ItemListChangeEventHandler([Of] ItemInfo)(AddressOf Me.OnItemsChanging)
            AddHandler Me.tabItemList.ListChanged, New ItemListChangeEventHandler([Of] ItemInfo)(AddressOf Me.OnItemsChanged)
            Me.buttonTips = New ToolTip
            Me.buttonTips.ShowAlways = True
            Me.buttonTips.SetToolTip(Me, String.Empty)
            Me.BackColor = SystemColors.Control
            MyBase.SetStyle((ControlStyles.OptimizedDoubleBuffer Or (ControlStyles.AllPaintingInWmPaint Or (ControlStyles.SupportsTransparentBackColor Or (ControlStyles.Selectable Or (ControlStyles.ResizeRedraw Or ControlStyles.UserPaint))))), True)
            MyBase.ResumeLayout
            AddHandler SystemEvents.UserPreferenceChanged, New UserPreferenceChangedEventHandler(AddressOf Me.SystemEvents_UserPreferenceChanged)
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                RemoveHandler SystemEvents.UserPreferenceChanged, New UserPreferenceChangedEventHandler(AddressOf Me.SystemEvents_UserPreferenceChanged)
            End If
            MyBase.Dispose(disposing)
        End Sub

        Private Function GetTabImageRectangle(ByVal tabItemInfo As ItemInfo) As Rectangle
            Dim index As Integer = Me.tabItemList.IndexOf(tabItemInfo)
            If (index < 0) Then
                Throw New ArgumentException(DR.GetString("ButtonInformationMissing", New Object(0  - 1) {}))
            End If
            Dim empty As Rectangle = Rectangle.Empty
            If ((Not tabItemInfo.Image Is Nothing) AndAlso (Me.drawItems.Length = Me.tabItemList.Count)) Then
                empty = Me.drawItems(index).TabItemRectangle
                empty.Inflate(-1, -1)
                empty.Size = New Size((Me.reqTabItemSize - 2), (Me.reqTabItemSize - 2))
            End If
            Return empty
        End Function

        Private Function GetTabItemRectangle(ByVal tabItemInfo As ItemInfo) As Rectangle
            Dim index As Integer = Me.tabItemList.IndexOf(tabItemInfo)
            If (index < 0) Then
                Throw New ArgumentException(DR.GetString("ButtonInformationMissing", New Object(0  - 1) {}))
            End If
            If (Me.drawItems.Length = Me.tabItemList.Count) Then
                Return Me.drawItems(index).TabItemRectangle
            End If
            Return Rectangle.Empty
        End Function

        Private Function GetTabTextRectangle(ByVal tabItemInfo As ItemInfo) As Rectangle
            Dim index As Integer = Me.tabItemList.IndexOf(tabItemInfo)
            If (index < 0) Then
                Throw New ArgumentException(DR.GetString("ButtonInformationMissing", New Object(0  - 1) {}))
            End If
            Dim empty As Rectangle = Rectangle.Empty
            If ((tabItemInfo.Text Is Nothing) OrElse (Me.drawItems.Length <> Me.tabItemList.Count)) Then
                Return empty
            End If
            empty = Me.drawItems(index).TabItemRectangle
            empty.Inflate(-1, -1)
            Dim tabImageRectangle As Rectangle = Me.GetTabImageRectangle(tabItemInfo)
            If Not tabImageRectangle.IsEmpty Then
                If (Me.orientation = Orientation.Horizontal) Then
                    empty.X = (empty.X + (tabImageRectangle.Width + 1))
                    empty.Width = (empty.Width - (tabImageRectangle.Width + 1))
                Else
                    empty.Y = (empty.Y + (tabImageRectangle.Height + 1))
                    empty.Height = (empty.Height - (tabImageRectangle.Height + 1))
                End If
            End If
            If ((empty.Width > 0) AndAlso (empty.Height > 0)) Then
                Return empty
            End If
            Return Rectangle.Empty
        End Function

        Private Sub OnItemsChanged(ByVal sender As Object, ByVal e As ItemListChangeEventArgs([Of] ItemInfo))
            If (Me.tabItemList.Count = 0) Then
                Me.selectedTab = -1
            ElseIf (Me.selectedTab > (Me.tabItemList.Count - 1)) Then
                Me.SelectedTab = (Me.tabItemList.Count - 1)
            End If
            If (Not MyBase.Parent Is Nothing) Then
                MyBase.Parent.PerformLayout
            End If
        End Sub

        Private Sub OnItemsChanging(ByVal sender As Object, ByVal e As ItemListChangeEventArgs([Of] ItemInfo))
            If (e.Action = ItemListChangeAction.Add) Then
                Dim info As ItemInfo
                For Each info In e.AddedItems
                    If Me.tabItemList.Contains(info) Then
                        Throw New ArgumentException(DR.GetString("Error_TabExistsWithSameId", New Object(0  - 1) {}))
                    End If
                Next
            End If
        End Sub

        Protected Overrides Sub OnLayout(ByVal levent As LayoutEventArgs)
            MyBase.OnLayout(levent)
            [Using] graphics As Graphics = MyBase.CreateGraphics
                Me.drawItems = New DrawTabItemStruct(Me.tabItemList.Count  - 1) {}
                Dim num As Integer = If((Me.orientation = Orientation.Horizontal), MyBase.Width, MyBase.Height)
                Dim flag As Boolean = False
                If (num <= Me.MinimumRequiredSize) Then
                    flag = True
                End If
                Dim num2 As Integer = 0
                Dim i As Integer
                For i = 0 To Me.tabItemList.Count - 1
                    Dim num4 As Integer = 0
                    Dim info As ItemInfo = Me.tabItemList.Item(i)
                    If (Not info.Image Is Nothing) Then
                        num4 += 1
                        num4 = (num4 + (Me.reqTabItemSize - 2))
                    End If
                    If ((Not info.Text Is Nothing) AndAlso (info.Text.Length > 0)) Then
                        Dim ef As SizeF = graphics.MeasureString(info.Text, Me.Font)
                        Me.drawItems(i).TextSize = New Size(Convert.ToInt32(Math.Ceiling(CDbl(ef.Width))), Convert.ToInt32(Math.Ceiling(CDbl(ef.Height))))
                        If Not flag Then
                            num4 = (num4 + (Me.drawItems(i).TextSize.Width + 1))
                        End If
                    End If
                    num4 = (num4 + If((num4 = 0), Me.reqTabItemSize, 1))
                    Me.drawItems(i).TabItemRectangle = Rectangle.Empty
                    If (Me.orientation = Orientation.Horizontal) Then
                        Me.drawItems(i).TabItemRectangle.X = num2
                        Me.drawItems(i).TabItemRectangle.Y = 0
                        Me.drawItems(i).TabItemRectangle.Width = num4
                        Me.drawItems(i).TabItemRectangle.Height = Me.reqTabItemSize
                    Else
                        Me.drawItems(i).TabItemRectangle.X = 0
                        Me.drawItems(i).TabItemRectangle.Y = num2
                        Me.drawItems(i).TabItemRectangle.Width = Me.reqTabItemSize
                        Me.drawItems(i).TabItemRectangle.Height = num4
                    End If
                    num2 = (num2 + (num4 + 1))
                Next i
                num2 -= 1
                If (num2 > num) Then
                    Dim num5 As Integer = CInt(Math.Ceiling(CDbl((CDbl((num2 - num)) / CDbl(Math.Max(1, Me.tabItemList.Count))))))
                    num2 = 0
                    Dim struct2 As DrawTabItemStruct = Me.drawItems((Me.tabItemList.Count - 1))
                    Dim num6 As Integer = If((Me.orientation = Orientation.Horizontal), (struct2.TabItemRectangle.Width - num5), (struct2.TabItemRectangle.Height - num5))
                    If (num6 < Me.reqTabItemSize) Then
                        num5 = (num5 + CInt(Math.Ceiling(CDbl((CDbl((Me.reqTabItemSize - num6)) / CDbl(Math.Max(1, Me.tabItemList.Count)))))))
                    End If
                    Dim j As Integer
                    For j = 0 To Me.tabItemList.Count - 1
                        If (Me.orientation = Orientation.Horizontal) Then
                            Me.drawItems(j).TabItemRectangle.X = (Me.drawItems(j).TabItemRectangle.X - num2)
                            Me.drawItems(j).TabItemRectangle.Width = (Me.drawItems(j).TabItemRectangle.Width - num5)
                            If ((j = (Me.tabItemList.Count - 1)) AndAlso (Me.drawItems(j).TabItemRectangle.Width < Me.reqTabItemSize)) Then
                                Me.drawItems(j).TabItemRectangle.Width = Me.reqTabItemSize
                            End If
                        Else
                            Me.drawItems(j).TabItemRectangle.Y = (Me.drawItems(j).TabItemRectangle.Y - num2)
                            Me.drawItems(j).TabItemRectangle.Height = (Me.drawItems(j).TabItemRectangle.Height - num5)
                            If ((j = (Me.tabItemList.Count - 1)) AndAlso (Me.drawItems(j).TabItemRectangle.Height < Me.reqTabItemSize)) Then
                                Me.drawItems(j).TabItemRectangle.Height = Me.reqTabItemSize
                            End If
                        End If
                        num2 = (num2 + num5)
                    Next j
                End If
            End [Using]
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            MyBase.OnMouseDown(e)
            Dim num As Integer = 0
            Dim info As ItemInfo
            For Each info In Me.tabItemList
                If Me.GetTabItemRectangle(info).Contains(New Point(e.X, e.Y)) Then
                    Me.SelectedTab = num
                    Exit For
                End If
                num += 1
            Next
        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal e As EventArgs)
            MyBase.OnMouseLeave(e)
            Me.buttonTips.SetToolTip(Me, String.Empty)
            MyBase.Invalidate
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
            MyBase.OnMouseMove(e)
            Dim info As ItemInfo
            For Each info In Me.tabItemList
                If (Me.GetTabItemRectangle(info).Contains(New Point(e.X, e.Y)) AndAlso (info.Text <> Me.buttonTips.GetToolTip(Me))) Then
                    Me.buttonTips.Active = False
                    Me.buttonTips.SetToolTip(Me, info.Text)
                    Me.buttonTips.Active = True
                    Exit For
                End If
            Next
            MyBase.Invalidate
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            MyBase.OnPaint(e)
            If (Me.drawItems.Length = Me.tabItemList.Count) Then
                e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias
                Dim color As Color = Color.FromArgb(&HFF, &HEE, &HC2)
                Dim color2 As Color = Color.FromArgb(&HFF, &HC0, &H6F)
                If SystemInformation.HighContrast Then
                    color = Color.FromArgb((&HFF - color.R), (&HFF - color.G), (&HFF - color.B))
                    color2 = Color.FromArgb((&HFF - color2.R), (&HFF - color2.G), (&HFF - color2.B))
                End If
                [Using] brush As Brush = New SolidBrush(color)
                    [Using] brush2 As Brush = New SolidBrush(color2)
                        Dim i As Integer
                        For i = 0 To Me.drawItems.Length - 1
                            Dim tabItemInfo As ItemInfo = Me.tabItemList.Item(i)
                            Dim struct2 As DrawTabItemStruct = Me.drawItems(i)
                            Dim control As Brush = SystemBrushes.Control
                            Dim tabItemRectangle As Rectangle = struct2.TabItemRectangle
                            If (Me.selectedTab = i) Then
                                control = brush2
                                e.Graphics.FillRectangle(control, tabItemRectangle)
                                e.Graphics.DrawRectangle(SystemPens.Highlight, tabItemRectangle)
                            Else
                                Dim pt As Point = MyBase.PointToClient(Control.MousePosition)
                                If tabItemRectangle.Contains(pt) Then
                                    control = brush
                                    e.Graphics.FillRectangle(control, tabItemRectangle)
                                    e.Graphics.DrawRectangle(SystemPens.ControlDarkDark, tabItemRectangle)
                                End If
                            End If
                            Dim tabImageRectangle As Rectangle = Me.GetTabImageRectangle(tabItemInfo)
                            If Not tabImageRectangle.IsEmpty Then
                                e.Graphics.DrawImage(tabItemInfo.Image, tabImageRectangle)
                            End If
                            Dim tabTextRectangle As Rectangle = Me.GetTabTextRectangle(tabItemInfo)
                            If Not tabTextRectangle.IsEmpty Then
                                Dim format As New StringFormat { _
                                    .Alignment = StringAlignment.Center, _
                                    .LineAlignment = StringAlignment.Center, _
                                    .Trimming = StringTrimming.EllipsisCharacter _
                                }
                                If (Me.orientation = Orientation.Horizontal) Then
                                    Dim layoutRectangle As New RectangleF(CSng(tabTextRectangle.X), CSng(tabTextRectangle.Y), CSng(tabTextRectangle.Width), CSng(tabTextRectangle.Height))
                                    e.Graphics.DrawString(tabItemInfo.Text, Me.Font, SystemBrushes.ControlText, layoutRectangle, format)
                                Else
                                    [Using] bitmap As Bitmap = New Bitmap(tabTextRectangle.Height, tabTextRectangle.Width, e.Graphics)
                                        [Using] graphics As Graphics = Graphics.FromImage(bitmap)
                                            graphics.TextRenderingHint = TextRenderingHint.AntiAlias
                                            graphics.FillRectangle(control, New Rectangle(0, 0, bitmap.Width, bitmap.Height))
                                            graphics.DrawString(Me.tabItemList.Item(i).Text, Me.Font, SystemBrushes.ControlText, New Rectangle(0, 0, bitmap.Width, bitmap.Height), format)
                                            bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone)
                                            e.Graphics.DrawImage(bitmap, tabTextRectangle)
                                        End [Using]
                                    End [Using]
                                End If
                            End If
                        Next i
                    End [Using]
                End [Using]
            End If
        End Sub

        Private Sub SystemEvents_UserPreferenceChanged(ByVal sender As Object, ByVal e As UserPreferenceChangedEventArgs)
            Me.buttonTips.BackColor = SystemColors.Info
            Me.buttonTips.ForeColor = SystemColors.InfoText
        End Sub


        ' Properties
        Public ReadOnly Property MaximumRequiredSize As Integer
            Get
                Dim num As Integer = 0
                If (Me.tabItemList.Count = Me.drawItems.Length) Then
                    Dim i As Integer
                    For i = 0 To Me.tabItemList.Count - 1
                        Dim info As ItemInfo = Me.tabItemList.Item(i)
                        Dim num3 As Integer = 0
                        If (Not info.Image Is Nothing) Then
                            num3 += 1
                            num3 = (num3 + Me.reqTabItemSize)
                        End If
                        If ((Not info.Text Is Nothing) AndAlso (info.Text.Length > 0)) Then
                            num3 += 1
                            num3 = (num3 + Me.drawItems(i).TextSize.Width)
                        End If
                        num3 = (num3 + If((num3 = 0), Me.reqTabItemSize, 1))
                        num = (num + num3)
                    Next i
                End If
                Return num
            End Get
        End Property

        Public ReadOnly Property MinimumRequiredSize As Integer
            Get
                Dim num As Integer = 0
                Dim i As Integer
                For i = 0 To Me.tabItemList.Count - 1
                    num = (num + (1 + Me.reqTabItemSize))
                Next i
                Return num
            End Get
        End Property

        Public Property SelectedTab As Integer
            Get
                Return Me.selectedTab
            End Get
            Set(ByVal value As Integer)
                If ((value >= 0) AndAlso (value <= Me.tabItemList.Count)) Then
                    Dim previousItem As ItemInfo = If(((Me.selectedTab >= 0) AndAlso (Me.selectedTab < Me.tabItemList.Count)), Me.tabItemList.Item(Me.selectedTab), Nothing)
                    Dim tabItemInfo As ItemInfo = Me.tabItemList.Item(value)
                    Me.selectedTab = value
                    MyBase.Invalidate
                    If (Not Me.TabChange Is Nothing) Then
                        Dim tabItemRectangle As Rectangle = Me.GetTabItemRectangle(tabItemInfo)
                        Me.TabChange.Invoke(Me, New TabSelectionChangeEventArgs(previousItem, tabItemInfo, New Rectangle(MyBase.PointToScreen(tabItemRectangle.Location), tabItemRectangle.Size)))
                    End If
                End If
            End Set
        End Property

        Public ReadOnly Property Tabs As IList([Of] ItemInfo)
            Get
                Return Me.tabItemList
            End Get
        End Property


        ' Fields
        Private buttonTips As ToolTip
        Private drawItems As DrawTabItemStruct()
        Private Const MinSize As Integer = &H12
        Private orientation As Orientation
        Private reqTabItemSize As Integer
        Private selectedTab As Integer = -1
        Private tabItemList As ItemList([Of] ItemInfo)
        Private Const TabMargin As Integer = 1

        ' Nested Types
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure DrawTabItemStruct
            Public TabItemRectangle As Rectangle
            Public TextSize As Size
        End Structure
    End Class
End Namespace

